package hu.veilingsite.gui;

import hu.veilingsite.client.Service;
import hu.veilingsite.client.ServiceAsync;
import hu.veilingsite.shared.Auction;
import hu.veilingsite.shared.Bid;
import hu.veilingsite.shared.Category;
import hu.veilingsite.shared.ClientUser;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;

public class Statistics {
	private VerticalPanel p;
	private FlowPanel monthPanel,weekPanel,dayPanel;
	private CellTable<Integer> tableYear = new CellTable<Integer>();
	private CellTable<Integer> tableMonth = new CellTable<Integer>();
	private CellTable<Integer> tableWeek = new CellTable<Integer>();
	private CellTable<Integer> tableDay = new CellTable<Integer>();
	private CellTable<Auction> auctionTable = new CellTable<Auction>();
	private Label lbname,highestBid,monthTable,weekTable,dayTable,lbBidAuthor,lbCategoryName,lbAuctionTitle,lbAuctionDescription,lbAuctionEndDate,lbAuctionTimeLeft,lbAuctionBeginPrice;
	private boolean removeMonth = false,removeWeek = false,removeDay = false;
	private int year,month,week,day;
	private String selectedRowType;
	private ArrayList<Integer> months = new ArrayList<Integer>();
	private ArrayList<Integer> weeks = new ArrayList<Integer>();
	private FlexTable layoutTable;
	
	final ServiceAsync myService = (ServiceAsync)
	GWT.create(Service.class);
	final AsyncCallback<ArrayList<Integer>> getYearCallback = new AsyncCallback<ArrayList<Integer>>() {
		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Error in getYearCallback.");
		}
		@Override
		public void onSuccess(ArrayList<Integer> result) {
			tableYear.setRowCount(result.size(),false);
			tableYear.setRowData(result);
		}
	};
	
	final AsyncCallback<Bid> getBidCallback = new AsyncCallback<Bid>() {
		@Override
		public void onFailure(Throwable caught) {
			layoutTable.setVisible(false);
			Window.alert("Fout tijdens het ophalen van het bod.");
		}
		@Override
		public void onSuccess(Bid result) {
			myService.getAuction(result.getAuction_id(),getAuctionCallback);
			myService.getUser(result.getUser_id(), getClientUserCallback);
			String name;
			if (selectedRowType == "year") {
				name = ""+year;
			} else if (selectedRowType == "month") {
				name = month+"/"+year;
			} else if (selectedRowType == "week") {
				name = year+" Week "+week;
			} else {
				name = day+"-"+month+"-"+year;
			}
			lbname.setText(name);
			highestBid.setText(result.getDate()+" Credits: "+result.getCredits());
		}
	};
	
	final AsyncCallback<Auction> getAuctionCallback = new AsyncCallback<Auction>() {
		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Fout tijdens het ophalen van de veiling.");
		}
		@Override
		public void onSuccess(Auction result) {
			lbAuctionTitle.setText(result.getTitle());
			lbAuctionDescription.setText(result.getDescription());
			lbAuctionEndDate.setText(""+result.getEndDate());
			lbAuctionTimeLeft.setText(timeLeft(result.getEndDate()));
			lbAuctionBeginPrice.setText(result.getStartprice()+" Credits");
			myService.getCategory(result.getId(),getCategoryCallback);
		}
	};
	
	final AsyncCallback<Category> getCategoryCallback = new AsyncCallback<Category>() {
		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Fout tijdens het ophalen van een categorie.");
		}
		@Override
		public void onSuccess(Category cat) {
			lbCategoryName.setText(cat.getTitle());
		}
	};
	
	final AsyncCallback<ClientUser> getClientUserCallback = new AsyncCallback<ClientUser>() {
		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Fout tijdens het ophalen van de biedergegevens.");
		}
		@Override
		public void onSuccess(ClientUser result) {
			lbBidAuthor.setText(result.getName());
		}
	};
	
	final AsyncCallback<ArrayList<Auction>> getAuctionsCallback = new AsyncCallback<ArrayList<Auction>>() {

		@Override
		public void onFailure(Throwable caught) {
			Window.alert("Fout tijdens het ophalen van biedingen.");
		}

		@Override
		public void onSuccess(ArrayList<Auction> result) {
			auctionTable.setRowCount(result.size(),false);
			auctionTable.setRowData(result);
		}
	};
	
	public Statistics() {
		for(int i=1;i<=12;i++) {
			months.add(i);
		}
		for(int i=1;i<=52;i++) {
			weeks.add(i);
		}
	}
	
	public VerticalPanel createPage() {
	p = new VerticalPanel();
	
	//meest beboden veilingen
	TextColumn<Auction> titleColumn = new TextColumn<Auction>() {
		@Override
		public String getValue(Auction auction) {
			return auction.getTitle();
		}
	};
	TextColumn<Auction> endDateColumn = new TextColumn<Auction>() {
		@Override
		public String getValue(Auction auction) {
			return auction.getEndDate().toString();
		}
	};
	TextColumn<Auction> numberOfBidsColumn = new TextColumn<Auction>() {
		@Override
		public String getValue(Auction auction) {
			return ""+auction.getNumberOfBids();
		}
	};
	auctionTable.setStyleName("tableCategories");
	auctionTable.addColumn(titleColumn);
	auctionTable.addColumn(endDateColumn);
	auctionTable.addColumn(numberOfBidsColumn);
	
	myService.getBestBidAuctions(getAuctionsCallback);
	
	p.add(new HTML("<h2>Best beboden veilingen</h2>"));
	p.add(auctionTable);
	
	//Statistics jaar/maand/week/dag
	layoutTable = new FlexTable();
	layoutTable.addStyleName("nicetable");
	
	lbname = new Label("");
	highestBid = new Label("");
	lbBidAuthor = new Label("");
	lbCategoryName = new Label("");
	lbAuctionTitle = new Label("");
	lbAuctionDescription = new Label("");
	lbAuctionEndDate = new Label("");
	lbAuctionTimeLeft = new Label("");
	lbAuctionBeginPrice = new Label("");
	
	layoutTable.setWidget(0,0,new Label("Wanneer:"));
	layoutTable.setWidget(0,1,lbname);
	layoutTable.setWidget(1,0,new Label("Hoogste Bod:"));
	layoutTable.setWidget(1,1,highestBid);
	layoutTable.setWidget(2,0,new Label("Geboden door:"));
	layoutTable.setWidget(2,1,lbBidAuthor);
	layoutTable.setWidget(3, 0, new Label("Veiling naam:"));
	layoutTable.setWidget(3, 1, lbAuctionTitle);
	layoutTable.setWidget(4, 0, new Label("Omschrijving: "));
	layoutTable.setWidget(4, 1,lbAuctionDescription);
	layoutTable.setWidget(5, 0, new Label("Loopt tot: "));
	layoutTable.setWidget(5, 1,lbAuctionEndDate);
	layoutTable.setWidget(6, 0, new Label("Tijd over: "));
	layoutTable.setWidget(6, 1,lbAuctionTimeLeft);
	layoutTable.setWidget(7, 0, new Label("Beginprijs: "));
	layoutTable.setWidget(7, 1,lbAuctionBeginPrice);
	layoutTable.setWidget(8, 0, new Label("Category: "));
	layoutTable.setWidget(8, 1,lbCategoryName);
	layoutTable.setVisible(false);
	p.add(layoutTable);
	
	//Year
	TextColumn<Integer> yearColumn = new TextColumn<Integer>() {
		@Override
		public String getValue(Integer year) {
			return ""+year;
		}
	};
	
	tableYear.setStyleName("tableCategories");
	tableYear.addColumn(yearColumn);
	myService.getYears(getYearCallback);
	p.add(new HTML("<h2>Hoogste biedingen:</h2>"));
	p.add(tableYear);
	final SingleSelectionModel<Integer> selectionModelYear = new SingleSelectionModel<Integer>();
	tableYear.setSelectionModel(selectionModelYear);
	selectionModelYear.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
		public void onSelectionChange(SelectionChangeEvent event) {
			layoutTable.setVisible(true);
			int selectedYear = selectionModelYear.getSelectedObject();
			updateStatistics("year",selectedYear);
			//Month
			try {
				if (removeMonth) {
					removeMonth = false;
					System.out.println("remove monthPanel");
					p.remove(monthPanel);
					monthPanel = null;
					tableMonth = null;
					tableMonth = new CellTable<Integer>();
				}
				if (removeWeek) {
					removeWeek = false;
					System.out.println("remove weekPanel");
					p.remove(weekPanel);
					weekPanel = null;
					tableWeek = new CellTable<Integer>();
				}
				if (removeDay) {
					p.remove(dayPanel);
					removeDay = false;
					tableDay = new CellTable<Integer>();
				}
			} catch(Exception e) {
				e.printStackTrace();
				//do nothing if tables where never created
			}
			TextColumn<Integer> monthColumn = new TextColumn<Integer>() {
				@Override
				public String getValue(Integer month) {
					return ""+month;
				}
			};
			tableMonth.setStyleName("tableCategories");
			tableMonth.addColumn(monthColumn);
			removeMonth = true;
			monthTable = new Label("Maanden:");
			monthPanel = new FlowPanel();
			monthPanel.add(monthTable);
			monthPanel.add(tableMonth);
			p.add(monthPanel);
			tableMonth.setRowCount(months.size(),false);
			tableMonth.setRowData(months);
			final SingleSelectionModel<Integer> selectionModelMonth = new SingleSelectionModel<Integer>();
			tableMonth.setSelectionModel(selectionModelMonth);
			selectionModelMonth.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
				public void onSelectionChange(SelectionChangeEvent event) {
					layoutTable.setVisible(true);
					int selectedMonth = selectionModelMonth.getSelectedObject();
					updateStatistics("month",selectedMonth);
					try {
						if (removeWeek) {
							removeWeek = false;
							p.remove(weekPanel);
							tableWeek = new CellTable<Integer>();
						}
						if (removeDay) {
							removeDay = false;
							p.remove(dayPanel);
							tableDay = new CellTable<Integer>();
						}
					} finally {
						//do nothing if tables where never created
					}
					TextColumn<Integer> dayColumn = new TextColumn<Integer>() {
						@Override
						public String getValue(Integer day) {
							return ""+day;
						}
					};
					tableDay.setStyleName("tableCategories");
					tableDay.addColumn(dayColumn);
					removeDay = true;
					dayTable = new Label("Dagen:");
					dayPanel = new FlowPanel();
					dayPanel.add(dayTable);
					dayPanel.add(tableDay);
					p.add(dayPanel);
					setDays("month");
					final SingleSelectionModel<Integer> selectionModelDay = new SingleSelectionModel<Integer>();
					tableDay.setSelectionModel(selectionModelDay);
					selectionModelDay.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
						public void onSelectionChange(SelectionChangeEvent event) {
							layoutTable.setVisible(true);
							int selectedDay = selectionModelDay.getSelectedObject();
							updateStatistics("day",selectedDay);
						}
					});
				}
			});
			TextColumn<Integer> weekColumn = new TextColumn<Integer>() {
				@Override
				public String getValue(Integer week) {
					return "Week "+week;
				}
			};
			tableWeek.setStyleName("tableCategories");
			tableWeek.addColumn(weekColumn);
			removeWeek = true;
			weekTable = new Label("Weken:");
			weekPanel = new FlowPanel();
			weekPanel.add(weekTable);
			weekPanel.add(tableWeek);
			p.add(weekPanel);
			tableWeek.setRowCount(weeks.size(),false);
			tableWeek.setRowData(weeks);
			final SingleSelectionModel<Integer> selectionModelWeek = new SingleSelectionModel<Integer>();
			tableWeek.setSelectionModel(selectionModelWeek);
			selectionModelWeek.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
				public void onSelectionChange(SelectionChangeEvent event) {
					layoutTable.setVisible(true);
					int selectedWeek = selectionModelWeek.getSelectedObject();
					updateStatistics("week",selectedWeek);
					try {
						if (removeDay) {
							removeDay = false;
							tableDay = new CellTable<Integer>();
							p.remove(dayPanel);
						}
					} finally {
						//do nothing if tables where never created
					}
					TextColumn<Integer> dayColumn = new TextColumn<Integer>() {
						@Override
						public String getValue(Integer day) {
							return ""+day;
						}
					};
					tableDay.setStyleName("tableCategories");
					tableDay.addColumn(dayColumn);
					removeDay = true;
					dayTable = new Label("Dagen:");
					dayPanel = new FlowPanel();
					dayPanel.add(dayTable);
					dayPanel.add(tableDay);
					p.add(dayPanel);
					setDays("week");
					final SingleSelectionModel<Integer> selectionModelDay = new SingleSelectionModel<Integer>();
					tableDay.setSelectionModel(selectionModelDay);
					selectionModelDay.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
						public void onSelectionChange(SelectionChangeEvent event) {
							layoutTable.setVisible(true);
							int selectedDay = selectionModelDay.getSelectedObject();
							updateStatistics("day",selectedDay);
						}
					});
				}
			});
		}
	});
	
	return p;
	}
	
	private void setDays(String type) {
		ArrayList<Integer> days = new ArrayList<Integer>();
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		if (type.equals("week")) {
			calendar.set(Calendar.WEEK_OF_YEAR, week);
			calendar.set(Calendar.YEAR, year);
			int maxDaysInMonth = calendar.getActualMaximum(calendar.DAY_OF_MONTH);
			if (calendar.DAY_OF_MONTH > (maxDaysInMonth-7)) {
				int daysInNextMonth = calendar.DAY_OF_MONTH - (maxDaysInMonth-7);
				for(int i=calendar.DAY_OF_MONTH;i<=(7-daysInNextMonth);i++) {
					days.add(i);
				}
				for(int i=1;i<=daysInNextMonth;i++) {
					days.add(i);
				}
			} else {
				for(int i=calendar.DAY_OF_MONTH;i<=(calendar.DAY_OF_MONTH+7);i++) {
					days.add(i);
				}
			}
		} else {
			calendar.set(Calendar.MONTH, (month-1));
			calendar.set(Calendar.YEAR, year);
			for(int i=1;i<=calendar.getActualMaximum(calendar.DAY_OF_MONTH);i++) {
				days.add(i);
			}
		}
		tableDay.setRowCount(days.size(),false);
		tableDay.setRowData(days);
	}
	
	private void updateStatistics(String type,int id) {
		selectedRowType = type;
		if (type == "year") {
			year = id;
			myService.getHighestBid("year",year,month,week,day,getBidCallback);
		} else if (type == "month") {
			month = id;
			myService.getHighestBid("month",year,month,week,day,getBidCallback);
		} else if (type == "week") {
			week = id;
			myService.getHighestBid("week",year,month,week,day,getBidCallback);
		} else if (type == "day") {
			day = id;
			myService.getHighestBid("day",year,month,week,day,getBidCallback);
		}
	}
	
	public String timeLeft(Date einddatum) {
		Date until = new Date(einddatum.getTime());
		Date now = new Date();
		String tijdover = "";
		long timeleft = until.getTime() - now.getTime();
		if(timeleft > 0){
			// Easy as that ;D
			long days = (long) Math.ceil(timeleft / (1000 * 60 * 60 * 24));
			timeleft = timeleft - (days * (1000 * 60 * 60 * 24));
			if(days > 0) tijdover += days + " dagen ";
			long hours = (long) Math.ceil(timeleft / (1000 * 60 * 60));
			timeleft = timeleft - (hours * (1000 * 60 * 60));
			if(hours > 0) tijdover += hours + " uur ";
			long min = (long) Math.ceil(timeleft / (1000 * 60));
			timeleft = timeleft - (min * (1000 * 60));
			if(min > 0) tijdover += min + " min ";
			long sec = (long) Math.ceil(timeleft / (1000));
			timeleft = timeleft - (sec * (1000));
			tijdover += sec + " sec.";
		}
		else{
			tijdover = "Veiling gesloten.";
		}
		return tijdover;
	}
}
